package com.zhkc.iess.auth.service;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zhkc.iess.auth.constant.RedisKeyConstant;
import com.zhkc.iess.auth.entity.SysUser;
import com.zhkc.iess.auth.dto.LoginInfoDTO;
import com.zhkc.iess.auth.vo.LoginInfoVO;
import com.zhkc.wisdom.common.base.context.SecurityConstants;
import com.zhkc.wisdom.common.base.context.SecurityContextHolder;
import com.zhkc.wisdom.common.base.enums.ErrorCodeEnum;
import com.zhkc.wisdom.common.base.exception.BusinessException;
import com.zhkc.wisdom.common.base.model.LoginContextInfo;
import com.zhkc.wisdom.common.redis.agent.RedisAgent;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class AuthService {

    @Autowired
    private RedisAgent redisAgent;

    @Autowired
    private SysUserService sysUserService;

    @Value("${login.fail-num:5}")
    private int failNum;

    @Value("${login.lock-time:300}")
    private int lockTime;

    @Value("${base.avatar}")
    private String avatar;

    public LoginInfoVO login(LoginInfoDTO dto) {
        //1、验证码校验
        authCaptcha(dto);
        //2、查询数据库的账号密码信息
        SysUser sysUser = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getAccount, dto.getAccount()));
        //3、判断账号是否被锁定
        Integer lockNum = checkUserLock(sysUser);
        //4、判断账户信息（账号、密码）
        checkUserInfo(dto, sysUser, lockNum);
        //5、登录成功：组装返回参数、清除验证码、登陆失败次数
        return loginSuccess(dto, sysUser);
    }


    /**
     * 验证码校验：过期、错误
     */
    private void authCaptcha(LoginInfoDTO dto) {
        if ("acbb".equals(dto.getCpCode())){
            //acbb直接跳过验证码验证
            return;
        }
        String cpCode = redisAgent.getString(RedisKeyConstant.KAPTCHA_SESSION_KEY + dto.getUuid());
        if (StrUtil.isEmpty(cpCode)) {
            throw BusinessException.thrown(ErrorCodeEnum.verification_code_invalid);
        }

        if (!cpCode.equals(dto.getCpCode())) {
            throw BusinessException.thrown(ErrorCodeEnum.verification_code_error);
        }
    }

    /**
     * 判断账号是否被锁定
     */
    private Integer checkUserLock(SysUser sysUser) {
        //判断账户是否存在
        if (sysUser == null) {
            throw BusinessException.thrown(ErrorCodeEnum.login_fail_error);
        }
        Integer lockNum = redisAgent.getObject(RedisKeyConstant.LOGIN_LOCK_PREFIX + sysUser.getAccount(), Integer.class);
        if (lockNum == null) {
            lockNum = 0;
        }
        if (lockNum >= failNum) {
            throw new BusinessException(StrUtil.format(ErrorCodeEnum.login_lock_error.getMsg(), lockTime / 60));
        }
        return lockNum;
    }


    public static void main(String[] args) {
        System.out.println(SaSecureUtil.sha256("111111"));
    }

    /**
     * 判断账户信息（账号、密码）、登陆失败次数
     */
    private void checkUserInfo(LoginInfoDTO dto, SysUser sysUser, Integer lockNum) {

        //验证密码
        String password = SaSecureUtil.sha256(dto.getPassword());
        if (!password.equals(sysUser.getPassword())) {
            //失败次数判定
            lockNum++;
            redisAgent.setObject(RedisKeyConstant.LOGIN_LOCK_PREFIX + sysUser.getAccount(), lockNum, lockTime, Integer.class);
            checkUserLock(sysUser);
            throw new BusinessException(StrUtil.format(ErrorCodeEnum.login_fail_lock_error.getMsg(), failNum - lockNum));
        }
    }

    /**
     * 登录成功：组装返回参数、清除验证码、登陆失败次数
     */
    private LoginInfoVO loginSuccess(LoginInfoDTO dto, SysUser sysUser) {
        LoginContextInfo loginAccount = new LoginContextInfo();
        loginAccount.setAccount(sysUser.getAccount());
        loginAccount.setAccountId(sysUser.getId());
        loginAccount.setOrgId(sysUser.getOrgId());
        loginAccount.setTenantId(sysUser.getTenantId());
        //增加info扩展，存入satoken，后续可以直接取出
        StpUtil.login(sysUser.getId(), SaLoginConfig
                .setExtra("info", loginAccount));
        loginAccount.setNickname(sysUser.getNickname());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        loginAccount.setTokenName(tokenInfo.tokenName);
        loginAccount.setTokenValue(tokenInfo.tokenValue);
        LoginInfoVO loginInfoVO = BeanUtil.copyProperties(loginAccount, LoginInfoVO.class);
        //清除验证码
        redisAgent.removeObject(RedisKeyConstant.KAPTCHA_SESSION_KEY + dto.getUuid());
        redisAgent.removeObject(RedisKeyConstant.LOGIN_LOCK_PREFIX + sysUser.getAccount());
        //查询角色code-List，返回给前端
        loginInfoVO.setRoleList(this.sysUserService.getBaseMapper().getRoleCodeList(sysUser.getId()));
        loginInfoVO.setAvatar(avatar + sysUser.getAvatar());
        return loginInfoVO;
    }

}




